package com.voda.service.impl;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.voda.dao.api.IRoleDao;
import com.voda.dao.api.IUserDao;
import com.voda.entity.Role;
import com.voda.entity.User;
import com.voda.errors.NotMatchPasswordException;
import com.voda.service.api.IUserService;

/**
 * The Class UserServiceImpl.
 */
@Service
public class UserServiceImpl implements IUserService {

	/** The Constant MD5. */
	private static final String MD5 = "MD5";

	/** The Constant ADMIN_ROLE_NAME. */
	private static final String ADMIN_ROLE_NAME = "admin";

	/** The user dao. */
	@Autowired
	private IUserDao userDao;
	
	/** The role dao. */
	@Autowired
	private IRoleDao roleDao;
	
	/**
	 * Generate hash for password.
	 *
	 * @param password the password
	 * @return the string
	 */
	private String generateHashForPassword(String password){
		try {
            MessageDigest md = MessageDigest.getInstance(MD5);
            md.update(password.getBytes());
            byte[] bytes = md.digest();
            StringBuilder sb = new StringBuilder();
            for(int i=0; i< bytes.length ;i++)
            {
                sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
            }
            return sb.toString();
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IGenericService#addRecord(java.lang.Object)
	 */
	@Override
	@Transactional
	public Long addRecord(User entity) {
		String password = generatePassword();
		entity.setPassword(generateHashForPassword(password));
		Long userId = userDao.addRecord(entity);
		entity.setPassword(password);
		return userId;
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IGenericService#deleteRecord(java.lang.Long)
	 */
	@Override
	@Transactional
	public void deleteRecord(Long id) {
		userDao.deleteRecord(id);
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IGenericService#updateRecord(java.lang.Object)
	 */
	@Override
	@Transactional
	public void updateRecord(User entity) {
		User user = userDao.getRecordById(entity.getId());
		user.setBlocked(entity.isBlocked());
		user.setRole(entity.getRole());
		user.setEmail(entity.getEmail());
		if(entity.getPassword() != null){
			entity.setPassword(generateHashForPassword(entity.getPassword()));
			user.setPassword(entity.getPassword());
		}
		userDao.updateRecord(user);
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IGenericService#getRecordById(java.lang.Long)
	 */
	@Override
	@Transactional
	public User getRecordById(Long id) {
		User result = userDao.getRecordById(id);
		result.setPassword(null);
		return result;
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IGenericService#getAll()
	 */
	@Override
	@Transactional
	public List<User> getAll() {
		List<User> users = userDao.getAll();
		for(User user : users){
			user.setPassword(null);
		}
		return users;
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IGenericService#getRecordsPage(java.lang.Integer, java.lang.Integer)
	 */
	@Override
	@Transactional
	public List<User> getRecordsPage(Integer startPage, Integer pageSize) {
		List<User> users = userDao.getRecordsPage(startPage, pageSize);
		for(User user : users){
			user.setPassword(null);
		}
		return users;
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IGenericService#count()
	 */
	@Override
	@Transactional
	public Integer count() {
		return userDao.count();
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IUserService#findUser(java.lang.String, java.lang.String)
	 */
	@Override
	@Transactional
	public User findUser(String login, String password) {
		User result = userDao.findUser(login, generateHashForPassword(password));
		if(result != null){
			result.setPassword(null);
		}
		return result;
	}
	
	/* (non-Javadoc)
	 * @see com.voda.service.api.IUserService#getUserWithRole(java.lang.Long)
	 */
	@Override
	@Transactional
	public User getUserWithRole(Long id) {
		User result = userDao.getUserWithRole(id);
		result.setPassword(null);
		return result;
	}


	/** The random. */
	private SecureRandom random = new SecureRandom();
	
	/**
	 * Generate password.
	 *
	 * @return the string
	 */
	private String generatePassword() {
		return new BigInteger(50, random).toString(32);
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IUserService#updateUserBlocking(java.lang.Long, java.lang.Boolean)
	 */
	@Transactional
	@Override
	public void updateUserBlocking(Long id,Boolean blocked) {
		User user = userDao.getRecordById(id);
		user.setBlocked(blocked);
		userDao.updateRecord(user);
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IUserService#resetPasswordByAdmin(com.voda.entity.User)
	 */
	@Override
	@Transactional
	public void resetPasswordByAdmin(User user) {
		String password = generatePassword();
		user.setPassword(password);
		updateRecord(user);
		user.setPassword(password);
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IUserService#resetPasswordByUser(java.lang.Long, java.lang.String, java.lang.String)
	 */
	@Override
	@Transactional
	public void resetPasswordByUser(Long userId, String oldPassword, String newPassword) throws NotMatchPasswordException {
		User user = userDao.getRecordById(userId);
		if(!generateHashForPassword(oldPassword).equals(user.getPassword())){
			throw new NotMatchPasswordException();
		}
		user.setPassword(newPassword);
		updateRecord(user);	
		user.setPassword(newPassword);
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IUserService#checkUnique(java.lang.String)
	 */
	@Override
	@Transactional
	public boolean checkUnique(String name) {
		return userDao.checkUnique(name);
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IUserService#updateUser(java.lang.Long, java.lang.String, java.lang.String, com.voda.entity.Role)
	 */
	@Override
	@Transactional
	public void updateUser(Long userId, String email, String name, Role role) {
		User user = userDao.getRecordById(userId);
		String oldEmail = user.getEmail();
		user.setEmail(email);
		user.setRole(role);
		userDao.updateRecord(user);
		if(!oldEmail.equals(email)) {
		}
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IUserService#getUserByEmail(java.lang.String)
	 */
	@Override
	@Transactional
	public User getUserByEmail(String email) {
		return userDao.getUserByEmail(email);
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IUserService#createUser(java.lang.String)
	 */
	@Override
	@Transactional
	public User createUser(String email) {
		return createUser(email, ADMIN_ROLE_NAME);
	}

	/* (non-Javadoc)
	 * @see com.voda.service.api.IUserService#createUser(java.lang.String, java.lang.String)
	 */
	@Override
	@Transactional
	public User createUser(String email, String roleName) {
			Role role = roleDao.getRoleByName(roleName);
		
		String userPassword = generatePassword();
		String passwordToDB = generateHashForPassword(userPassword);
		User user = new User();
		user.setEmail(email);
		user.setRole(role);
		user.setPassword(passwordToDB);
		user.setBlocked(false);
		userDao.addRecord(user);
		user.setPassword(userPassword);
		return user;
	}
}
